package org.reference.generic.work;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;

import org.reference.generic.base.Item;
import org.reference.generic.base.Parameter;
import org.reference.generic.base.ReferenceParameter;
import org.reference.generic.information.Gene;
import org.reference.generic.work.Machine.OnCompleteListenner;

import util.Log;

/**
 * 
 */
public class Schedule extends Item implements MachineManager.OnCompleteListenner{

	
    /** 
     * 
     */
	
	MachineManager mm = new MachineManager();
	
	
    public Schedule() {
    	setName("SCHEDULE");

    }

    /**
     * 
     */
    private double fitness;
   
    
    List<ReferenceParameter> rpList;
    
    int index;
    /**
     * 
     */
    private ArrayList<Job> jobList;

    /**
     * 
     */
    
    private OnCompleteListenner onCompleteListenner;
    /**
     * @param onCompleteListenner
     */
    public void setOnCompleteListenner(OnCompleteListenner onCompleteListenner) {
        this.onCompleteListenner = onCompleteListenner;
    }
  
    private Gene gene;

    /**
     * @return
     */
    public double fitnessCalculation() {
        
    	fitness=mm.getCMAX();
    	
        return fitness;
    }

    /**
     * @return
     */
    
    
    /**
     * @param gene
     */
    public void setGene(Gene gene) {
        this.gene=gene;
    }

    /**
     * @return
     */
    public Gene getGene() {
        return gene;
    }

    /**
     * @return
     */
	public Job getNextJob() {

		if (isAvailable()==true) {

		double minValue = 100000;
		int minIndex = -1;
		
		gene.getRootNode().setMachineManager(mm);
		
		for (int i = 0; i < jobList.size(); i++) 
		{
			for (int j = 0; j < mm.getMachineIndex().size(); j++) 
			{
				gene.getRootNode().setJob(rpList.get(index).getJob(i));
				Log.debug("======사용 된 잡 인덱스"+ gene.getRootNode().getJob().getJobIndex() + " PT "+ gene.getRootNode().getJob().getProcessingTime());
				if(!mm.getMachineIndex().get(j).isBusy())
				{
					gene.getRootNode().setMachine(mm.getMachineIndex().get(j));
					
				}
				Log.debug("======사용 된 머신 인덱스"+ gene.getRootNode().getMachine().getIndex() + " 머신 RM "+ gene.getRootNode().getMachine().getReadyTime());
				Log.debug("======사용 된 머신 매니저 CT "+ mm.getCurrentTime());
				Log.debug(" =======사용 된 거를 이용한 진 계산값 " + gene.calculateGene());	
					
				double temp = gene.calculateGene();
				
				if (minValue > temp) 
					{
						minValue = temp;
						minIndex = i;
					
					}
			}
			
			
		}
		
		Log.debug(gene.getName() + " =======최종 선택된 진 계산값 "+ gene.calculateGene());
		Job returnJob = jobList.get(minIndex);

		jobList.remove(returnJob);

		Log.debug("!!!!!!!!!!!!!!!!!!!!#############선택된 잡============ " + returnJob.getJobIndex());
		Log.debug("#############선택 후 잡 갯수 " + jobList.size() + "===========");

		return returnJob;
		} else {
			return null;
		}
	}

    /**
     * @return
     */
    public boolean isAvailable() {
       
    	for(int i=0 ; i<mm.getMachineIndex().size();i++){
    		if(jobList.size()<0 && mm.getMachineIndex().get(i).isBusy())
    		{
    		return false;
    		}
    	}
    	return true;
    }
    
    public ArrayList<Job> getJobList() {
		return jobList;
	}

	public void setJobList(ArrayList<Job> jobList) {
		this.jobList = jobList;
	}

	public double getFitness() {
		return fitness;
	}

	public void setFitness(double fitness) {
		this.fitness = fitness;
	}
	
	
	public void scheduleParameter(int index, Parameter parameters, List<ReferenceParameter> rpList, Gene gene ){   
		
		setGene(gene);
		this.index=index;
		this.rpList= rpList;
		this.jobList=new ArrayList<Job>(rpList.get(index).getJobList());
		
		for(int i=0;i<jobList.size();i++){
			jobList.get(i).setJobIndex(i);
		}

		mm.setIndex(index);
		mm.init(parameters, rpList);
		mm.setOnCompleteListenner(this);
	}
	
	public void run(){

			mm.run(this);
			
		
		}
	
	@Override
	public void onComplete(MachineManager machineManager) {
		
		//fitnessCalculation(); //Fitness 에다가 Cmax 넣음..
		
		//Log.debug("스케줄 인덱스 "+index); // 스케줄 갯수  
		//Log.debug("스케줄의 피트니스 " +getFitness());
		
		//Log.debug("머신 매니저가 가지고 있는 머신의 갯수 "+machineManager.getMachineIndex().size());
		//for(int i=0;i<machineManager.getMachineIndex().size();i++){
//			Log.debug("머신 인덱스 "+ machineManager.getMachineIndex().get(i).getIndex());
//			for(int j=0;j<machineManager.getMachineIndex().get(i).getMachineSchedule().size();j++){
//				Log.debug(machineManager.getMachineIndex().get(i).getMachineSchedule().get(j).getJobIndex()+"\t");
//			}
//		}
		
		
		
//		for(int i=0;i<machineManager.getMachineIndex().size();i++){
//		System.out.println("머신 매니저가 가지고 있는 머신이 가지고 있는 잡의 갯수 "+machineManager.getMachineIndex().get(i).getMachineSchedule().size());
//		}
//		for(int i=0;i<machineManager.getMachineIndex().size();i++)
//			for(int j=0;j<machineManager.getMachineIndex().get(i).getMachineSchedule().size();j++){
//				System.out.println("머신별 스케줄 " +machineManager.getMachineIndex().get(i).getMachineSchedule().get(j));
//			}
		
		
//		for(int i=0;i<machineManager.getMachine().getMachineSchedule().size();i++)
//		{
//			System.out.print(" "+machineManager.getMachine().getMachineSchedule().get(i));
//		}
		
		
		if (onCompleteListenner == null) return;
    	onCompleteListenner.onComplete(this);  // 머신 매니저의 onComplete 호출 	
    	
    	//onComplete(machineManager);
    	
    
	}
	
	public interface OnCompleteListenner {
        /**
         * 
         */
        public abstract void onComplete(Schedule schedule);

    }

	public int getIndex() {
		return index;
	}

	public MachineManager getMm() {
		return mm;
	}

}
